package com.aop;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.neo4j.ogm.session.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.core.annotation.Order;
import org.springframework.data.neo4j.transaction.Neo4jTransactionManager;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.stereotype.Component;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.DefaultTransactionDefinition;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.PersistenceContext;
import java.util.List;

@Aspect
@Component
public class TransactionAspect {

    @PersistenceContext
    private EntityManager entityManager;

    /**
     * 定义neo4j事务管理器
     * @param sessionFactory
     * @return
     */
    @Bean("neo4jTransactionManager")
    public Neo4jTransactionManager neo4jTransactionManager(SessionFactory sessionFactory) {
        return new Neo4jTransactionManager(sessionFactory);
    }

    /**
     * 定义mysql事务管理器，必须有transactionManager作为默认事务管理器
     * @param emf
     * @return
     */
    @Bean("transactionManager")
    public JpaTransactionManager jpaTransactionManager(EntityManagerFactory emf) {
        return new JpaTransactionManager(emf);
    }


    @Autowired
    @Qualifier("neo4jTransactionManager")
    Neo4jTransactionManager neo4jTransactionManager;
    @Autowired
    @Qualifier("transactionManager")
    JpaTransactionManager jpaTransactionManager;

    @Around("@annotation(MultiTransaction)")
    public Object multiTransaction(ProceedingJoinPoint proceedingJoinPoint) {
        TransactionStatus neo4jTransactionStatus = neo4jTransactionManager.getTransaction(new DefaultTransactionDefinition());
        TransactionStatus jpaTransactionStatus = jpaTransactionManager.getTransaction(new DefaultTransactionDefinition());
        try {
            Object obj = proceedingJoinPoint.proceed();
            //注意：事务之间必须是包含关系，不能交叉
            jpaTransactionManager.commit(jpaTransactionStatus);
            neo4jTransactionManager.commit(neo4jTransactionStatus);
            return obj;
        } catch (Throwable throwable) {
            jpaTransactionManager.rollback(jpaTransactionStatus);
            neo4jTransactionManager.rollback(neo4jTransactionStatus);
            throw new RuntimeException(throwable);
        }
    }

    // 删除jpa托管状态
    @Around("@annotation(Detach)")
    public Object DatabaseDetach(ProceedingJoinPoint proceedingJoinPoint) {
        try {
            Object result = proceedingJoinPoint.proceed();
            if(result == null) return null;

            if(result instanceof List) {
                ((List) result).forEach(data -> {
                    entityManager.detach(data);
                });
            }else {
                entityManager.detach(result);
            }
            return result;
        }catch (Throwable throwable) {
            throw new RuntimeException(throwable);
        }
    }

}
